package com.example.distributeLock;

/**
 * 实现一个秒杀功能
 * 1.有人买 锁住、在里面执行
 */
public class origFunc {
    public static Long stock = 1L;

    /* 下单 */
    /*方式一  最初级。 会出现超卖，Thread-1 秒杀成功，Thread-2 秒杀成功，Thread-0 秒杀成功*/
//    public static void placeOrder() throws InterruptedException {
//        if (stock > 0) {
//            Thread.sleep(100);
//            stock--;
//            System.out.println(Thread.currentThread().getName() + " 秒杀成功");
//        } else {
//            System.out.println(Thread.currentThread().getName() + " 秒杀失败！库存不足");
//        }
//    }

    /*方式二  加上同步锁synchronized。解决超卖问题*/
    public static void placeOrder() throws InterruptedException {
        synchronized (stock) {
            if (stock > 0) {
                Thread.sleep(100);
                stock--;
                System.out.println(Thread.currentThread().getName() + " 秒杀成功");
            } else {
                System.out.println(Thread.currentThread().getName() + " 秒杀失败！库存不足");
            }
        }
    }


    /*并发量高的情况下，服务器压力越来越大==>nginx。经过压测 吞吐量上来了、但又出现超卖问题
    * 同步锁的问题，因为同步锁是jvm级别的、只能锁住单线程。——解决方案 分布式锁（主流分布式锁解决方案 redis、zookeeper）*/

    /**
     * 通过redis的SetNX实现分布式锁，setNx  无值 上锁成功，有值 上锁失败。一定要加上过期时间（防止某台服务器挂掉）
     *
     * 随着业务扩展，又暴露出来问题，当业务处理时间超过锁的过期时间
     * 1）当锁过期时线程还在处理业务中【其他线程会趁虚而入】——加长时间，并添加子线程每10s确认线程是否在线，在线则将过期时间重设
     * 2）当处理完释放其他线程的锁——给锁加唯一ID（UUID）
     * 自己实现较麻烦、且易出现bug，Redis是否有提供相关组件  -->  Redisson
     */




    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    placeOrder();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        System.out.println("stock=" + stock);
    }

    /*  方式一
    stock=1
    Thread-1 秒杀成功
    Thread-2 秒杀成功
    Thread-0 秒杀成功

    stock=1
    Thread-0 秒杀成功
    Thread-1 秒杀成功
    Thread-2 秒杀成功
     */

    /* 方式二
    stock=1
    Thread-0 秒杀成功
    Thread-2 秒杀失败！库存不足
    Thread-1 秒杀失败！库存不足
     */

}
